package com.ehome.poct.core.dao.mybatis;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ehome.mybatisplus.support.AbstractCrudRepository;
import com.ehome.poct.core.api.common.Age;
import com.ehome.poct.core.api.dto.common.Sex;
import com.ehome.poct.core.api.dto.patient.*;
import com.ehome.poct.core.api.vo.patient.PatientDetailVO;
import com.ehome.poct.core.dao.entity.TermPatientDO;
import com.ehome.poct.core.dao.entity.check.CheckReportDO;
import com.ehome.poct.core.dao.mapping.PatientMapping;
import com.ehome.poct.core.dao.mybatis.mapper.BldReportMapper;
import com.ehome.poct.core.dao.mybatis.mapper.PatientMapper;
import com.ehome.poct.core.repository.PatientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Optional;

@Repository
public class PatientRepositoryImpl extends AbstractCrudRepository<TermPatientDO, AddPatientDTO> implements PatientRepository {

    @Autowired private PatientMapper patientMapper;

    @Autowired private BldReportMapper bldReportMapper;

    @Autowired private PatientMapping patientMapping;

    /**
     * 添加患者
     * @param addPatientDto
     * @return
     */
    @Override
    public PatientDetailVO addPatient(AddPatientDTO addPatientDto){
        final var patient = this.toPatient(addPatientDto);
        final var patientDO = this.toPatientDO(patient);
        patientDO.insert();
        return patientMapping.toVO(patientDO);
    }


    /**
     * 修改患者
     * @param editPatientDto
     */
    @Override
    public PatientDetailVO editPatient(EditPatientDTO editPatientDto) {
        var patient = toPatient(patientMapper.selectById(editPatientDto.getPatientId()));
        patient.setDetail(new PatientDetail(editPatientDto.getUserName(),Sex.findByValue(editPatientDto.getUserSex()),editPatientDto.getMobilePhone(),new Age(editPatientDto.getUserAge(),editPatientDto.getUserMonth())));
        var patientDO =toPatientDO(patient);
        patientMapper.updateById(patientDO);
        bldReportMapper.update(null, Wrappers.<CheckReportDO>lambdaUpdate()
                .eq(CheckReportDO::getPatientId, editPatientDto.getPatientId())
                .ne(CheckReportDO::getPatientName, editPatientDto.getUserName())
                .set(CheckReportDO::getPatientName, editPatientDto.getUserName())
                .set(CheckReportDO::getUpdateTime, LocalDateTime.now()));
        return patientMapping.toVO(patientDO);
    }

    /**
     * 获取患者详情
     * @param patientId
     * @return
     */
    @Override
    public PatientDetailVO getPatient(Long patientId) {
        var termPatientDO = patientMapper.selectById(patientId);
        return patientMapping.toVO(termPatientDO);
    }

    @Override
    public Patient findById(Long patientId) {
        return this.toPatient(patientMapper.selectById(patientId));
    }


    private Patient toPatient(AddPatientDTO cmd) {
        return new Patient(cmd.getClinicId(),
                new PatientDetail(cmd.getUserName(), Sex.findByValue(cmd.getUserSex()), cmd.getMobilePhone(), new Age(cmd.getUserAge(), cmd.getUserMonth())));
    }


    public TermPatientDO toPatientDO(Patient patient) {
        final var detail = patient.getDetail();
        return new TermPatientDO().setTermPatientId(patient.getId()).setIsDelete(false)
                .setTermClinicId(patient.getClinicId()).setName(detail.getName())
                .setPhone(detail.getPhone()).setAge(detail.getAge().getYear() == null ? null : BigDecimal.valueOf(detail.getAge().getYear()))
                .setMonth(detail.getAge().getMonth()).setSex(detail.getSex().getValue()).setIsDelete(false);
    }

    public Patient toPatient(TermPatientDO entity) {
        return new Patient(entity.getTermPatientId(), entity.getTermClinicId(), toDetail(entity));
    }

    public PatientDetail toDetail(TermPatientDO patientDO) {
        return new PatientDetail(patientDO.getName(), Sex.findByValue(patientDO.getSex()), patientDO.getPhone(),
                new Age(Optional.ofNullable(patientDO.getAge()).map(a -> a.intValue()).orElse(null), patientDO.getMonth()));
    }
}
